/*
 * @Author: wwssaabb
 * @Date: 2021-12-10 17:39:21
 * @LastEditTime: 2021-12-11 08:06:31
 * @FilePath: \handwritten-code\main\继承.js
 */

//手写实现JS继承

//原型链继承

function Animal() {
  this.colors = ['black', 'white']
}
Animal.prototype.getColor = function () {
  return this.colors
}

function Dog() {}
Dog.prototype = new Animal()

let dog = new Dog()
console.log(dog.colors)
let dog2 = new Dog()
dog2.colors[0] = 'yellow'
console.log(dog.colors)

/* 
  缺点：
    1.无法向父类构造函数传参
    2.原型中包含的引用类型会被所有实例共享
*/

//借用构造函数继承
function Animal(name) {
  this.name = name
  this.getName = function () {
    return this.name
  }
}

function Cat(name) {
  Animal.call(this, name)
}

Cat.prototype = new Animal

/* 
  解决了传参问题，但每次创建子类的实例的时候都会创建一遍方法
*/

//组合继承（原型链继承+借用构造函数继承）

function Animal(name) {
  this.name = name
}
Animal.prototype.getName = function () {
  return this.name
}

function Cat(name, age) {
  Animal.call(this, name)
  this.age = age
}

Cat.prototype = new Animal()
Cat.prototype.constructor = Cat

/* 
  结合前面两种的优点，既能有自己的属性又能在原型上实现方法的复用
  缺点：调用了两次父类构造函数
*/

//寄生式组合继承
//通过空函数F获取父类原型的副本实现

function Animal(name) {
  this.name = name
}
Animal.prototype.getName = function () {
  return this.name
}

function Cat(name, age) {
  Animal.call(this, name)
  this.age = age
}

//和上面区别在这里
function F() {}
F.prototype = Animal.prototype
let f = new F()
f.constructor = Cat
Cat.prototype = f
//也可以简写成下面的写法
Cat.prototype = Object.create(Animal.prototype)
Cat.prototype.constructor = Cat


//Class实现继承 extends语法表示继承
class Animal {
  constructor(name) {
    this.name = name
  }
  getName() {
    return this.name
  }
}

class Cat extends Animal {
  constructor(name, age) {
    super(name)
    this.age = age
  }
}